package com.jh.complicate.io.nio;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author Administrator
 * @projectName newforward
 * @title NIOServer.java
 * @package com.jh.complicate.io.nio
 * @description NIO服务端
 * @date 2019/6/17 23:00
 */
public class NIOServer {

    private int port;
    private Selector selector;
    private ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

    public NIOServer(int port) {
        try {
            this.port = port;
            // 开门营业
            ServerSocketChannel server = ServerSocketChannel.open();
            // 告诉顾客地址
            server.bind(new InetSocketAddress(port));
            // 设置异步
            server.configureBlocking(false);
            // 大堂经理开始接客
            selector = Selector.open();
            // 翻开门店牌子，告诉客人开始接待
            server.register(selector, SelectionKey.OP_ACCEPT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void listen() {
        System.out.println("listen on  " + port);

        try {
            // 一直在叫号
            while (true) {
                // 大堂经理在叫号
                selector.select();
                // 拿到所有的号码牌
                Set<SelectionKey> keys = selector.selectedKeys();

                Iterator<SelectionKey> iterator = keys.iterator();
                // 同步体现在这里，每次只能拿一个key，每次只能处理一种状态
                while (iterator.hasNext()) {
                    SelectionKey key = iterator.next();
                    // key代表一种状态，每种状态给出对应的处理方法
                    process(key);
                    iterator.remove();
                }

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void process(SelectionKey key) {
        // 每一个号对应一个客户，每个客户都有不同的状态，有可以准备喝茶了，正在喝茶了，还有准备给钱了
        try {
            if (key.isAcceptable()) {
                // 可以读了
                ServerSocketChannel server = (ServerSocketChannel) key.channel();
                // 这里是非阻塞的，不管数据有没有准备好也要给一个状态和反馈
                SocketChannel channel = server.accept();
                channel.configureBlocking(false);
                // 更改状态为可读
                channel.register(selector, SelectionKey.OP_READ);
            } else if (key.isReadable()) {
                // key.channel()从多路复用器拿到客户端的引用
                SocketChannel channel = (SocketChannel) key.channel();
                int len = channel.read(byteBuffer);
                if (len > 0) {
                    byteBuffer.flip();
                    String conent = new String(byteBuffer.array(), 0, len);
                    System.out.println("read content：" + conent);
                    key = channel.register(selector, SelectionKey.OP_WRITE);
                    // 携带附件写出去
                    key.attach(conent);
                }
            } else if (key.isWritable()) {
                SocketChannel channel = (SocketChannel) key.channel();
                // 写附件出去
                String content = (String) key.attachment();
                channel.write(ByteBuffer.wrap(("write：" + content).getBytes()));
                // 最后关闭
                channel.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        new NIOServer(8080).listen();
    }
}
